package DoExercise.HSP_ZCY.A008_树.A001_普通二叉树.二叉树递归套路_找可能性;

import java.util.LinkedList;


/**
 * 完全二叉树：
 * 当二叉树的深度为h时，它的h层节点必须都是连续靠左并不可隔开的(满二叉树也符合)，并且1～h-1层的结点数都达到最大个数(即1~h-1层为一个满二叉树)。
 */
public class Code06_是不是完全二叉树
{
    
    public static class Node
    {
        public int value;
        public Node left;
        public Node right;
        
        public Node(int data)
        {
            this.value = data;
        }
    }
    
    public static boolean isCBT1(Node head)
    {
        if (head == null)
        {
            return true;
        }
        LinkedList<Node> queue = new LinkedList<>();
        // 是否遇到过左右两个孩子不双全的节点
        boolean leaf = false;
        Node l = null;
        Node r = null;
        queue.add(head);
        while (!queue.isEmpty())
        {
            head = queue.poll();
            l = head.left;
            r = head.right;
            //1 找到了叶子节点，后面的节点必须全部为空 2 左树为空，右树不为空。两种情况直接是false
            if ((leaf && !(l == null && r == null)) || (l == null && r != null))
            {
                return false;
            }
            if (l != null)
            {
                queue.add(l);
            }
            if (r != null)
            {
                queue.add(r);
            }
            if (l == null || r == null)
            {
                leaf = true;
            }
        }
        return true;
    }
    
    public static boolean isCBT2(Node head)
    {
        if (head == null)
        {
            return true;
        }
        return process(head).isCBT;
    }
    
    public static class Info
    {
        public boolean isFull;
        public boolean isCBT;
        public int height;
        
        public Info(boolean full, boolean cbt, int h)
        {
            isFull = full;//满二叉树
            isCBT = cbt;//完全二叉树
            height = h;//树的高度
        }
    }
    
    /**
     *
     *
     * 分为4种情况考虑
     *
     * @param head
     * @return
     */
    public static Info process(Node head)
    {
        if (head == null)
        {
            return new Info(true, true, 0);
        }
        Info leftInfo = process(head.left);
        Info rightInfo = process(head.right);
        int height = Math.max(leftInfo.height, rightInfo.height) + 1;
        boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;//左树是满的，右树是满的，高度也一样，就是满二叉树
        boolean isCBT = false;//是否是完全二叉树
        if (isFull)
        {
            isCBT = true;
        } else
        {
            if (leftInfo.isCBT && rightInfo.isCBT)
            {
                //左树是完全二叉树，右侧是满二叉树，且 左侧的树高度比右侧高度+1
                if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1)
                {
                    isCBT = true;
                }
                //左树是满二叉树，右侧是满二叉树，且 左侧的树高度比右侧高度+1
                if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1)
                {
                    isCBT = true;
                }
                //左树是满二叉树，右侧是完全二叉树，且 左侧的树高度和右侧高度一样
                if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height)
                {
                    isCBT = true;
                }
            }
        }
        return new Info(isFull, isCBT, height);
    }
    
    // for test
    public static Node generateRandomBST(int maxLevel, int maxValue)
    {
        return generate(1, maxLevel, maxValue);
    }
    
    // for test
    public static Node generate(int level, int maxLevel, int maxValue)
    {
        if (level > maxLevel || Math.random() < 0.5)
        {
            return null;
        }
        Node head = new Node((int) (Math.random() * maxValue));
        head.left = generate(level + 1, maxLevel, maxValue);
        head.right = generate(level + 1, maxLevel, maxValue);
        return head;
    }
    
    public static void main(String[] args)
    {
        int maxLevel = 5;
        int maxValue = 100;
        int testTimes = 1000000;
        for (int i = 0; i < testTimes; i++)
        {
            Node head = generateRandomBST(maxLevel, maxValue);
            if (isCBT1(head) != isCBT2(head))
            {
                System.out.println("Oops!");
            }
        }
        System.out.println("finish!");
    }
    
}
